package me.zhengjie.modules.management.service.impl;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import io.swagger.models.auth.In;
import lombok.RequiredArgsConstructor;
import me.zhengjie.domain.EmailConfig;
import me.zhengjie.domain.vo.EmailVo;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.management.domain.*;
import me.zhengjie.modules.management.mapper.*;
import me.zhengjie.modules.management.service.ConferenceRecordService;
import me.zhengjie.modules.management.service.EmailDtoService;
import me.zhengjie.modules.management.service.dto.*;
import me.zhengjie.modules.management.service.webservice.K3CloudTrigger;
import me.zhengjie.modules.management.service.webservice.K3CloudTriggerPortType;
import me.zhengjie.modules.system.domain.Dept;
import me.zhengjie.modules.system.repository.DeptRepository;
import me.zhengjie.modules.system.repository.UserRepository;
import me.zhengjie.service.EmailService;
import me.zhengjie.utils.PageHelpResultUtil;
import me.zhengjie.utils.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Author: yuchao.wang
 * @Date: 2020/12/15
 * @Description :
 */
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class ConferenceRecordServiceImpl implements ConferenceRecordService {

    private final ConferenceRecordMapper conferenceRecordMapper;

    private final ConferenceRoomMapper conferenceRoomMapper;

    private final UserMapper userMapper;

    private final OAMapper oaMapper;

    private final MrRecordDtlMapper mrRecordDtlMapper;

    private final MrConferencePurposeMapper mrConferencePurposeMapper;

    private final DeptRepository deptRepository;

    private final EmailService emailService;

    private final EmailDtoService emailDtoService;


    @Override
    public Map<String, Object> searchRecord(ConferenceRecordQueryCriteria conferenceRecordQueryCriteria, Pageable pageable) {
        PageHelper.startPage(pageable.getPage(), pageable.getSize());
        List<RecordDto> recordDtoList = conferenceRecordMapper.searchRecord(conferenceRecordQueryCriteria);
        for (RecordDto recordDto : recordDtoList) {
            recordDto.setApplicantName(userMapper.findNameById(recordDto.getApplicantId().longValue()));
            List<MrRecordDtlDto> mrRecordDtlDtoList = mrRecordDtlMapper.getListById(recordDto.getRecordId());
            recordDto.setMrRecordDtlDto(mrRecordDtlDtoList);
//            List<MrMaterialDtl> mrMaterialDtlList = null;
//            if (mrRecordDtlDtoList != null) {
//                for (MrRecordDtlDto mrRecordDtlDto : mrRecordDtlDtoList) {
//                    mrMaterialDtlList.add(mrMaterialDtlMapper.getMrMaterialDtlById(mrRecordDtlDto.getMaterialId()));
//
//                }
//                recordDto.setMrMaterialDtls(mrMaterialDtlList);
//
//            }
        }
            PageInfo<ConferenceRecord> pageInfo = new PageInfo(recordDtoList);
            return PageHelpResultUtil.toPage(pageInfo);
        }



    @Override
    public Map<String, Object> queryByCriteria(ConferenceRecordQueryCriteria conferenceRecordQueryCriteria, Pageable pageable) {
        PageHelper.startPage(pageable.getPage(), pageable.getSize());
        List<RecordDto> conferenceRecordList = conferenceRecordMapper.queryByCriteria(conferenceRecordQueryCriteria);
        if (conferenceRecordList!=null){
            for (RecordDto recordDto:conferenceRecordList)
            {
                //通过申请人id查到部门id，再查询到部门名称
                recordDto.setDeptName(deptRepository.findNameById(userMapper.queryDeptIdByUserId((recordDto.getApplicantId()).longValue())));
                recordDto.setApplicantName(userMapper.findNameById(recordDto.getApplicantId().longValue()));
                recordDto.setMrRecordDtlDto(mrRecordDtlMapper.getListById(recordDto.getRecordId()));
            }
        }
        PageInfo<RecordDto> pageInfo = new PageInfo(conferenceRecordList);
        return PageHelpResultUtil.toPage(pageInfo);
    }




    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(RecordDto resources) {

        // 字段非空校验
        nullTypeTest(resources);
        isFree(resources);
        // 插入预约信息
        try {
            if(resources.getBeginDate().after(new Date())){
                if(resources.getEndDate().after(resources.getBeginDate())){
                    resources.setStatus(2);
                    //预约的时候没有物资，是否准备默认状态“是”
                    if(resources.getMrMaterialDtls().size()<1){
                        resources.setIsReady(true);
                    }
                    conferenceRecordMapper.insertConferenceRecord(resources);
                    int recordId=resources.getRecordId();

                    //算出能源费用进行更新
            /*BigDecimal roomCost = mrRecordDtlMapper.getRoomCost(recordId);
            ConferenceRecord conferenceRecord = new ConferenceRecord();
            conferenceRecord.setRecordId(recordId);
            conferenceRecord.setRoomCost(roomCost);
            conferenceRecordMapper.updateCost(conferenceRecord);*/


                    List<MrMaterialDtl> mrMaterialDtlList=resources.getMrMaterialDtls();


                    BigDecimal workTime=conferenceRecordMapper.getTime(recordId);

                    if(mrMaterialDtlList!=null){
                        for(MrMaterialDtl mrMaterialDtl:mrMaterialDtlList)
                        {
                            MrRecordDtl mrRecordDtl=new MrRecordDtl();
                            mrRecordDtl.setRecordId(recordId);
                            mrRecordDtl.setMaterialId(mrMaterialDtl.getMaterialId());
                            mrRecordDtl.setPrice(mrMaterialDtl.getMaterialPrice());
                            mrRecordDtl.setRemark(mrMaterialDtl.getRemark());
                            mrRecordDtl.setCreateDateTime(new Timestamp(new Date().getTime()));
                            mrRecordDtl.setCreateUserId(SecurityUtils.getCurrentUsername());
                            if(mrMaterialDtl.getTypeId()==0) {
                                mrRecordDtl.setStatus(0);
                                mrRecordDtl.setNumber(BigDecimal.valueOf(resources.getUserNumber()));
                            }
                            else if   (mrMaterialDtl.getTypeId()==1){
                                mrRecordDtl.setStatus(1);
                                mrRecordDtl.setNumber(workTime);
                            }
                            mrRecordDtlMapper.addMrRecordDtl(mrRecordDtl);

                            System.err.println(mrRecordDtl.toString()+"=================");
                        }

                        //算出物资费用插入
                /*BigDecimal materialCost = mrRecordDtlMapper.getMaterialCost(recordId);
                conferenceRecord.setRecordId(recordId);
                conferenceRecord.setMaterialsCost(materialCost);
                conferenceRecordMapper.updateCost(conferenceRecord);*/
                    }
                }else{
                    //前端已判断
                    throw new BadRequestException("开始时间应在预约时间之后！");
                }
            }else{
                throw new BadRequestException("开始时间应在当前时间之前！");
            }

        } catch (Exception e) {
            throw new BadRequestException("预约失败，开始时间请在当前时间之后！");
        }
        //预约成功后发起OA申请
        K3CloudTrigger trigger=new K3CloudTrigger();
        K3CloudTriggerPortType k3CloudTriggerHttpPort = trigger.getK3CloudTriggerHttpPort();
        //构造OA需要传的参数
        //根据申请人ID获取部门id后获取部门code //sqrbm
        String deptId = userMapper.findDeptIdById(resources.getApplicantId().longValue());
        String deptCode = oaMapper.findDeptCodeById(deptId);
        //申请日期 sqrq
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        /*Timestamp createDateTime = resources.getCreateDateTime();*/
        String createDateTime = sdf.format(new Date(resources.getCreateDateTime().getTime()));
        //根据申请人ID获取工号 sqr,sqrgh,gsmc
        RoomUser user = userMapper.findUserById(resources.getApplicantId().longValue());
        String userName = user.getUserName();
        String orgCode = user.getOrgCode();
        //开始时间，结束时间,人数,编号 sykssj,syjssj，cypxrs,sqdbh

        String beginDate = sdf.format(new Date(resources.getBeginDate().getTime()));
        String endDate = sdf.format(new Date(resources.getEndDate().getTime()));
        /*Timestamp beginDate = resources.getBeginDate();
        Timestamp endDate = resources.getEndDate();*/
        Integer userNumber = resources.getUserNumber();
        Integer recordId=resources.getRecordId();
        //申请原因 sqyy
        String memo = resources.getMemo();
        //申请需求和费用 jsfwxq,fy
        List<MrMaterialDtl> request=resources.getMrMaterialDtls();
        StringBuffer stringBuffer=new StringBuffer();
        if (request.size()>0){
            for (MrMaterialDtl dtl : request) {
                Integer materialId = dtl.getMaterialId();
                String materialName = oaMapper.findMaterialNameById(materialId);
                stringBuffer.append(materialName+",");
            }
        }
        String req=null;
        if (stringBuffer.length()>0){
            req = stringBuffer.deleteCharAt(stringBuffer.length() - 1).toString();
        }
        BigDecimal roomCost = mrRecordDtlMapper.getRoomCost(recordId);
        BigDecimal materialCost = mrRecordDtlMapper.getMaterialCost(recordId);
        //培训类型,教室地点 pxlx,jsdd
        Integer typeId = resources.getTypeId();
        String purpose = oaMapper.findPurposeById(typeId);
        Integer roomId = resources.getRoomId();
        String roomName = conferenceRoomMapper.findRoomById(roomId);
        //构造json数组
        JsonArray jsonArray=new JsonArray();
        JsonObject jsonObject = new JsonObject();
        JsonObject header=new JsonObject();
        header.addProperty("sqdbh",recordId);
        header.addProperty("sqr",userName);
        header.addProperty("sqrgh",userName);
        header.addProperty("sqrbm", deptCode);
        header.addProperty("gsmc", orgCode);
        header.addProperty("sqrq", createDateTime);
        header.addProperty( "pxlx", purpose);
        header.addProperty("jsdd", roomName);
        header.addProperty("sykssj", beginDate);
        header.addProperty("syjssj",endDate);
        header.addProperty("fy",roomCost.doubleValue()+materialCost.doubleValue());
        header.addProperty("jsfwxq", req);
        header.addProperty( "cypxrs", userNumber);
        header.addProperty("sqyy", memo);
        jsonObject.add("HEADER", header);
        jsonObject.add("DETAILS", new JsonObject());
        jsonObject.addProperty("CREATERCODE",userName);
        jsonObject.addProperty("requestid",0);
        jsonArray.add(jsonObject);
        System.out.println(jsonArray);
        //发起OA申请
        String json = k3CloudTriggerHttpPort.triggerService(jsonArray.toString(), "classroom-management");
        //处理返回信息，获取requestId
        JSONObject object =JSONObject.parseObject(json);
        String requestId;
        if (object!=null){
            requestId= (String) object.get("requestid");
            oaMapper.insertRequest(recordId,Integer.parseInt(requestId));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(ConferenceRecordDto resources) {


        // 编辑预约状态
        /*try {
            //更改会议状态
            resources.setStatus(3);
            conferenceRecordMapper.updateConferenceRecord(resources);

        } catch (RuntimeException e) {
            throw new BadRequestException("更新操作失败！");
        }*/
        resources.setStatus(3);
        resources.setModifyUserId(SecurityUtils.getCurrentUsername());
        resources.setModifyDateTime(new Timestamp(new Date().getTime()));
        Timestamp endDate = resources.getEndDate();
        Timestamp beginDate = resources.getBeginDate();

        if(endDate.after(beginDate)){
            //获取此教室下一个会议开始时间，如果结束时间改了大于之后会议的开始时间的，抛异常
            List<Timestamp> nextBegainTime = conferenceRecordMapper.getNextBegainTime(resources);
            if(nextBegainTime.size()>0){
                Timestamp min = Collections.min(nextBegainTime);
                if(endDate.getTime()>min.getTime()){
                    throw new BadRequestException("结束时间超出下个会议的开始时间！");
                }else{
                    conferenceRecordMapper.updateConferenceRecord(resources);
                }
            }else{
                    conferenceRecordMapper.updateConferenceRecord(resources);
            }


        }else{
            throw new BadRequestException("会议结束时间不能小于开始时间！");
        }

       /* conferenceRecordMapper.updateConferenceRecord(resources);*/



        //准备完成后发送邮件通知申请人
        //获取申请人email
        String email = userMapper.findEmailById(conferenceRecordMapper.findApplicantIdByRecordId(resources.getRecordId()));
        //获取邮件信息
        EmailDto emailDto = emailDtoService.getEmailDto(resources.getRecordId());
        /*System.out.println(emailDto+"===============================================");*/
        if (ObjectUtil.isNotEmpty(email)){
            sendEmail(email,emailDto);
        }
    }

    /**1.查询开始时间是今天或者之前、结束时间是当前时间之后的会议
    * 2.判断开始时间
    *   开始时间在今天，默认使用beginDate；
    *   开始时间在今天之前，设置开始时间为0点；
    * 3.结束时间判断
    *   结束时间在今天，默认使用endDate；
    *   结束时间大于今天，设置结束时间为23:59:59
    * */
    @Override
    public List<ConferenceRecord> findNotExpiredRecord(){
        //查询1.结束时间在本周(大于第一天小于最后一天)；2.开始时间在本周结束时间在下周的会议；3.开始时间本周之前、结束时间本周之后的会议
        List<ConferenceRecord> list=conferenceRecordMapper.getWeekRecord();
        //定义存放本周未过期的会议集合
        List<ConferenceRecord> listNotExpired=new ArrayList<>();
        for (ConferenceRecord conferenceRecord:list) {
            conferenceRecord.setUserName(userMapper.findNameById(conferenceRecord.getApplicantId().longValue()));
            conferenceRecord.setRoomName(conferenceRoomMapper.findRoomById(conferenceRecord.getRoomId()));
            //获取当天0点时间
            long current = System.currentTimeMillis();
            long zero = current/(1000*3600*24)*(1000*3600*24) - TimeZone.getDefault().getRawOffset();
            Timestamp zeroTime = new Timestamp(zero);
            //判断结束时间是否到下周
            if(conferenceRecord.getEndDate().after(Timestamp.valueOf(conferenceRecordMapper.getNextWeekFirstDay()+" 00:00:00"))){
                Long currentTimestamps = Timestamp.valueOf(conferenceRecordMapper.getWeekLastDay()+" 00:00:00").getTime();
                Long oneDayTimestamps = Long.valueOf(60 * 60 * 24 * 1000);
                Long endTime=currentTimestamps - (currentTimestamps + 60 * 60 * 8 * 1000) % oneDayTimestamps + 24 * 60 * 60 * 1000 - 1000;
                Timestamp end = new Timestamp(endTime);
                conferenceRecord.setEndDate(end);
            }
            //开始时间在当天之前
            if(conferenceRecord.getBeginDate().before(zeroTime)){
                conferenceRecord.setBeginDate(zeroTime);
                listNotExpired.add(conferenceRecord);
            //开始时间是当天
            }else if(isToday(conferenceRecord.getBeginDate())){
                listNotExpired.add(conferenceRecord);
            //开始时间大于当天
            }else if(conferenceRecord.getBeginDate().after(new Timestamp(zero+86400000))){
                listNotExpired.add(conferenceRecord);
            }
        }
        return listNotExpired;
    }

    /**
     * 判断时间戳是否是当天
     * @param date
     * @return
     */
    private  Boolean isToday(Timestamp date){
        Timestamp t = new Timestamp(date.getTime());
        Date d = new Date(t.getTime());
        SimpleDateFormat fmt=new SimpleDateFormat("yyyy-MM-dd");
        if(fmt.format(d).equals(fmt.format(new Date()))){
            return true;
        }else {
            return false;
        }
    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<RecordDto> findById(Integer recordId){
        List<RecordDto> list=conferenceRecordMapper.findById(recordId);
        for (RecordDto recordDto:list) {
            recordDto.setRoomName(conferenceRoomMapper.findRoomById(recordDto.getRoomId()));
            recordDto.setApplicantName(userMapper.findNameById(recordDto.getApplicantId().longValue()));
            recordDto.setPurposeName(mrConferencePurposeMapper.getMrConferencePurposeById(recordDto.getTypeId()).getPurposeName());
            recordDto.setDeptName(deptRepository.findNameById(userMapper.findDeptIdById((recordDto.getApplicantId()).longValue())));
            recordDto.setRoomCost(mrRecordDtlMapper.getRoomCost(recordId));
        }
        //带出会议物资的明细列表
        for (RecordDto recordDto:list) {
            recordDto.setMrRecordDtlDto(mrRecordDtlMapper.getListById(recordDto.getRecordId()));
        }
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BigDecimal getTime(Integer recordId){
        return conferenceRecordMapper.getTime(recordId);
    }

   /* @Override
    public void deleteRecord(RecordDto recordDto) {
        Long s = (recordDto.getBeginDate().getTime()-System.currentTimeMillis()) / (1000 * 60);
        if(s>30){
           if(recordDto.getStatus()==3){
               conferenceRecordMapper.deleteRecord(recordDto.getRecordId());
           }else{
               throw new BadRequestException("会议未审核通过，无法删除！");
           }
        }else{
            throw new BadRequestException("距离会议开始不到半小时，无法取消！");
        }
    }*/

    @Override
    public void cancelRecord(RecordDto recordDto) {
        Long s = (recordDto.getBeginDate().getTime()-System.currentTimeMillis()) / (1000 * 60);
        if(s>30){
            if(recordDto.getStatus()==3){
                recordDto.setStatus(8);
                recordDto.setModifyUserId(SecurityUtils.getCurrentUsername());
                recordDto.setModifyDateTime(new Timestamp(new Date().getTime()));
                conferenceRecordMapper.updateRecordById(recordDto);
            }else{
                throw new BadRequestException("会议未审核通过，无法取消！");
            }
        }else{
            throw new BadRequestException("距离会议开始不到半小时，无法取消！");
        }
    }


    /**
     * 对字段进行非空校验（FOrgID,FDeptID,FPostCode,FPostName）
     *
     * @param resources
     * @return void
     */
    public void nullTypeTest(RecordDto resources) {

        if (ObjectUtil.isNull(resources.getTypeId())) {
            throw new BadRequestException("会议类型不能为空！");
        }

        if (ObjectUtil.isNull(resources.getSubject())) {
            throw new BadRequestException("会议名称不能为空！");
        }

        if (ObjectUtil.isNull(resources.getMemo())) {
            throw new BadRequestException("会议申请原因不能为空！");
        }

        if (ObjectUtil.isNull(resources.getRoomId())) {
            throw new BadRequestException("教室ID不能为空！");
        }

        if (ObjectUtil.isNull(resources.getRoomName())) {
            throw new BadRequestException("会议室名称不能为空！");
        }
        if (ObjectUtil.isNull(resources.getUserNumber())) {
            throw new BadRequestException("参会人数不能为空！");
        }
        if (ObjectUtil.isNull(resources.getBeginDate())) {
            throw new BadRequestException("开始日期不能为空！");
        }
        if (ObjectUtil.isNull(resources.getEndDate())) {
            throw new BadRequestException("结束日期不能为空！");
        }
        if (ObjectUtil.isNull(resources.getExtNo())) {
            throw new BadRequestException("短号不能为空！");
        }
    }
    public void isFree(RecordDto resources){
        TimeDto timeDto=new TimeDto();
        timeDto.setRoomId(resources.getRoomId());
        timeDto.setBeginDate(resources.getBeginDate());
        timeDto.setEndDate(resources.getEndDate());
        if(conferenceRecordMapper.IsFree(timeDto)!=0){
            throw new BadRequestException("该时间段已存在预约，请勿重复!");
        }

    }

    /**
     * 构造邮件，发邮件
     * @return
     */
    public void sendEmail(String email,EmailDto emailDto){
        EmailVo emailVo = new EmailVo();
        emailVo.setSubject("大学教室管理系统");
        Map<String, Object> data = new HashMap<>(16);
        data.put("trainingName",emailDto.getSubject());
        data.put("address",emailDto.getRoomName());
        data.put("type",emailDto.getTypeName());
        data.put("numberOfPeople",emailDto.getUserNumber());
        data.put("beginTime",emailDto.getBeginDate());
        data.put("endTime",emailDto.getEndDate());
        data.put("applicant",emailDto.getApplicant());
        data.put("dept",emailDto.getApplicantDept());
        List<MrRecordDtlDto> materialDtl=emailDto.getMaterialDtl();
        data.put("materialDtl",materialDtl);
        /*System.out.println(materialDtl+"================");*/
        TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
        Template template = engine.getTemplate("email/readyEmail.ftl");
        emailVo.setContent(template.render(data));

        //List<String> emails = Arrays.asList(quartzJob.getEmail().split("[,，]"));
        List<String> emails = new ArrayList<String>();
        emails.add(email);
        emailVo.setTos(emails);
        EmailConfig emailConfig = emailService.find();
        System.out.println(emailConfig.toString());
        emailService.send(emailVo,emailConfig);
    }
}
